package com.hhy.lombok.utils;

import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.code.TypeTag;
import com.sun.tools.javac.comp.AttrContext;
import com.sun.tools.javac.comp.Env;
import com.sun.tools.javac.model.JavacElements;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.TreeMaker;
import com.sun.tools.javac.util.DiagnosticSource;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.ListBuffer;
import com.sun.tools.javac.util.Name;

import javax.lang.model.element.Modifier;

import java.util.Set;

import static com.hhy.lombok.constant.Constant.CONSTRUCTOR_NAME;
import static com.hhy.lombok.constant.Constant.THIS;
import static com.sun.tools.javac.util.List.nil;

/**
 * Created with IntelliJ IDEA.
 *
 * @author hai-yang
 * @date 2022/04/21/23:10
 * @description
 */
public class JCUtils {


    /**
     * 创建变量
     * Object a = new Object();
     * @param varName 名字
     * @param varClass 类型
     * @param varValue 初始化语句
     * @param modifiers 访问修饰符
     * @return
     */
    public static JCTree.JCVariableDecl createVar(TreeMaker treeMaker, Name varName, JCTree.JCExpression varClass, JCTree.JCExpression varValue, Long modifiers) {
        return treeMaker.VarDef(
                treeMaker.Modifiers(modifiers),
                varName,
                varClass,
                varValue
        );
    }

    /**
     * 生成 创建实例的语句
     * @param treeMaker
     * @param className
     * @return
     */
    public static JCTree.JCExpression createInstance(TreeMaker treeMaker, Name className) {
        return treeMaker.NewClass(
                null,
                List.nil(), // 泛型参数列表
                treeMaker.Ident(className), // 要实例化的类
                List.nil(), // 参数列表
                null);
    }

    public static JCTree.JCMethodDecl createMethod(TreeMaker treeMaker, Name methodName, JCTree.JCExpression returnType, List<JCTree.JCVariableDecl> params,
                                                   List<JCTree.JCExpression> jcThrows, JCTree.JCBlock block, long modifier) {
        return treeMaker.MethodDef(
                treeMaker.Modifiers(modifier), //访问标志
                methodName, //名字
                returnType, //返回类型
                List.nil(), //泛型形参列表
                params, //参数列表
                jcThrows, //异常列表
                block, //方法体
                null); //默认方法（可能是interface中的那个default）
    }

    /**
     * 创建代码块
     * @param treeMaker
     * @param jcStatements
     * @return
     */
    public static JCTree.JCBlock createBlock(TreeMaker treeMaker, List<JCTree.JCStatement> jcStatements) {
        return treeMaker.Block(0L, jcStatements);
    }

    /**
     * 创建赋值语句
     * obj.field = value;
     */
    public static JCTree.JCExpressionStatement createAssignStatement(TreeMaker treeMaker, JCTree.JCIdent obj, Name field, JCTree.JCIdent value) {
        return treeMaker.Exec(
                treeMaker.Assign(treeMaker.Select(obj, field), value)
        );
    }

    /**
     * 创建return语句
     * @param treeMaker
     * @param obj
     * @param field
     * @param castType
     * @return
     */
    public static JCTree.JCReturn createReturn(TreeMaker treeMaker, JCTree.JCIdent obj, Name field, JCTree.JCExpression castType) {
        // 强转
        if (castType != null) {
            JCTree.JCExpression val = obj;
            if (field != null) {
                val = treeMaker.Select(obj, field);
            }
            return treeMaker.Return(
                    treeMaker.TypeCast(castType, val)
            );
        }

        if (field != null) {
            return treeMaker.Return(
                    treeMaker.Select(obj, field)
            );
        } else {
            return treeMaker.Return(obj);
        }
    }

    /**
     * 生成可执行语句
     * @param treeMaker
     * @param varName
     * @param methodName
     * @param params
     * @return
     */
    public static JCTree.JCExpressionStatement callMethod(TreeMaker treeMaker, JavacElements elementUtils, String varName, String methodName, List<JCTree.JCExpression> params) {
        JCTree.JCExpression left;
        if (varName.contains(".")) {
            left = memberAccess(treeMaker, elementUtils, varName);
        } else {
            left = treeMaker.Ident(elementUtils.getName(varName));
        }

        return treeMaker.Exec(
                treeMaker.Apply(
                        nil(),
                        treeMaker.Select(left,
                                elementUtils.getName(methodName) // 右边的内容
                        ),
                        params
                )
        );
    }


    /**
     * 返回 null
     * @param treeMaker
     * @return
     */
    public static JCTree.JCLiteral returnNone(TreeMaker treeMaker) {
        return treeMaker.Literal(TypeTag.BOT, null);
    }

    /**
     * cp 一个变量
     * @param treeMaker
     * @param oVar
     * @return
     */
    public static JCTree.JCVariableDecl copyVar(TreeMaker treeMaker, JCTree.JCVariableDecl oVar) {
        return treeMaker.VarDef(
                oVar.getModifiers(),
                oVar.getName(),
                oVar.vartype,
                oVar.getInitializer()
        );
    }


    /**
     * 获取所有字段
     *
     * @param jcClass 类的语法树节点
     * @return 字段的语法树节点的集合
     */
    public static List<JCTree.JCVariableDecl> getJClassFields(JCTree.JCClassDecl jcClass) {
        ListBuffer<JCTree.JCVariableDecl> jcVariables = new ListBuffer<>();
        for (JCTree jcTree : jcClass.defs) {
            if (isValidField(jcTree)) {
                jcVariables.append((JCTree.JCVariableDecl) jcTree);
            }
        }
        return jcVariables.toList();
    }

    public static List<JCTree.JCVariableDecl> copyVar2Param(TreeMaker treeMaker, List<JCTree.JCVariableDecl> oVars) {
        ListBuffer<JCTree.JCVariableDecl> jcVariables = new ListBuffer<>();
        for (JCTree.JCVariableDecl oVar : oVars) {
            jcVariables.append(
                    treeMaker.VarDef(
                            treeMaker.Modifiers(Flags.PARAMETER),
                            oVar.getName(),
                            oVar.vartype,
                            oVar.getInitializer()
                    )
            );
        }
        return jcVariables.toList();
    }

    /**
     * 判断是否是合法的字段
     *
     * @param jcTree 语法树节点
     * @return 是否是合法字段
     */
    private static boolean isValidField(JCTree jcTree) {
        if (jcTree.getKind().equals(JCTree.Kind.VARIABLE)) {
            JCTree.JCVariableDecl jcVariable = (JCTree.JCVariableDecl) jcTree;
            Set<Modifier> flagSets = jcVariable.mods.getFlags();
            return !flagSets.contains(Modifier.STATIC) && !flagSets.contains(Modifier.FINAL);
        }
        return false;
    }

    public static JCTree.JCExpression memberAccess(TreeMaker treeMaker, JavacElements elementUtils, String className) {
        String[] componentArray = className.split("\\.");
        JCTree.JCExpression expr = treeMaker.Ident(elementUtils.getName(componentArray[0]));
        for (int i = 1; i < componentArray.length; i++) {
            expr = treeMaker.Select(expr, elementUtils.getName(componentArray[i]));
        }
        return expr;
    }

    public static List<JCTree.JCVariableDecl> copyVars(TreeMaker treeMaker, List<JCTree.JCVariableDecl> jClassFields) {
        ListBuffer<JCTree.JCVariableDecl> jcVariables = new ListBuffer<>();
        for (JCTree.JCVariableDecl jcVariable : jClassFields) {
            jcVariables.append(copyVar(treeMaker, jcVariable));
        }
        return jcVariables.toList();
    }

    public static JCTree getTree(String treePath, JavacElements elementUtils) {
        Symbol.ClassSymbol typeElement = elementUtils.getTypeElement(treePath);
        if (typeElement == null) {
            return null;
        }
        return elementUtils.getTree(typeElement);
    }
}
